﻿// vcpkg.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <opencv2/opencv.hpp>

static bool leastSquaresFit(const std::vector<cv::Point>& ps, double& K, double& B)
{
	int n = ps.size();
	double sum_x = 0, sum_y = 0, sum_xy = 0, sum_x2 = 0, sum_y2 = 0;

	// 计算各项总和
	for (int i = 0; i < n; ++i) 
	{
		sum_x += ps[i].x;
		sum_y += ps[i].y;
		sum_xy += ps[i].x * ps[i].y;
		sum_x2 += ps[i].x * ps[i].x;
		sum_y2 += ps[i].y * ps[i].y;
	}

	// 计算斜率 k 和截距 b
	double denominator = n * sum_x2 - sum_x * sum_x;
	if (denominator == 0) {
		throw std::runtime_error("无法拟合垂直线");
	}

	double k = (n * sum_xy - sum_x * sum_y) / denominator;
	double b = (sum_y - k * sum_x) / n;

	// 计算拟合优度 R²
	double y_mean = sum_y / n;
	double ss_tot = 0, ss_res = 0;

	for (int i = 0; i < n; ++i) {
		double y_pred = k * ps[i].x + b;
		ss_tot += (ps[i].y - y_mean) * (ps[i].y - y_mean);
		ss_res += (ps[i].y - y_pred) * (ps[i].y - y_pred);
	}

	double r2 = 1.0 - (ss_res / ss_tot);

	K = k;
	B = b;	
}

int main()
{
	std::cout << "Hello World!\n";

	std::string imagePath = R"(1.jpg)"; // 替换为你的图片路径
	cv::Mat image = cv::imread(imagePath, cv::IMREAD_COLOR);

	if (image.empty()) {
		std::cerr << "Could not open or find the image!\n";
		return -1;
	}

	auto roiRect = cv::selectROI("Image", image, true, false);
	cv::destroyAllWindows(); // 销毁所有窗口

	auto roi = image(roiRect); // 获取选中的ROI区域
	cv::Mat grayRoi;
	cv::cvtColor(roi, grayRoi, cv::ColorConversionCodes::COLOR_RGB2GRAY);



	std::vector<cv::Point> roiCenterPix{};
	for (int r = 0; r < grayRoi.rows; r++)
	{
		std::vector<uchar> pixValue{};
		for (int c = 0; c < grayRoi.cols; c++)
		{
			pixValue.push_back(grayRoi.at<uchar>(r, c));
		}

		// 计算斜率
		int maxC = 0; double maxK = 0;
		int offset = 3;
		for (int i = offset; i < grayRoi.cols; i++)
		{
			double k = std::abs(pixValue.at(i) / pixValue.at(i - offset));
			if (k > maxK)
			{
				maxC = i;
				maxK = k;
			}
		}

		roi.at<cv::Vec3b>(r, maxC)[0] = 0;
		roi.at<cv::Vec3b>(r, maxC)[1] = 0;
		roi.at<cv::Vec3b>(r, maxC)[2] = 255;

		roiCenterPix.push_back(cv::Point(r, maxC));
	}

	cv::waitKey(0); // 等待按键事件
	return 0;

}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
